package model;

import controller.Controller;

/**
 * @author Colin
 * 
 * The Zombosaur class handles health speed, damage, position, 
 * name, and whether the zombosaur is alive or not. 
 *
 */
public abstract class Zombosaur {
	
	private final int flyawaySpeed = 10;

	private int speed;
	private int currentSpeed;
	private int remainingHealth;
	private int damage;
	private TrailTile currentTile;
	private float xPos;	//in fractions of grid coordinates
	private float yPos;   //in fractions of grid coordinates
	private int direction = 0;	//angle in degrees where 0 = facing right on the screen
	private boolean alive;
	private boolean finishedDying;
	private int hitAngle = 180;	//the angle that the zombosaur was last hit from. used for making the zombosaur fly off the screen
	private String name;
	private String imageName1;
	private String imageName2;
	private String currentImageName;
	private float stepPeriod = 0.5f;	//duration of time between each step of the zombosaurs image
	private int tickCounter = 0;
	
	public Zombosaur(String name, String imageName1, String imageName2, int speed, int health, int damage, TrailTile startingCoordinate){
		this.speed = speed;
		currentSpeed = speed;
		this.remainingHealth = health;
		this.damage = damage;
		this.name = name;
		this.imageName1 = imageName1;
		this.imageName2 = imageName2;
		this.currentImageName = imageName1;
		this.currentTile = startingCoordinate;
		this.xPos = (float)this.currentTile.getX()+0.5f;
		this.yPos = (float)this.currentTile.getY()+0.5f;
		alive = true;
		finishedDying = false;
	}
	
	/**
	 * Returns the description of the zombosaur. All subclasses
	 * must implement.
	 */
	public abstract String getDescription(); 
	
	/**
	 * What happens when the zombosaur gets hit by a weapon 
	 * or defensive item
	 * @param damage
	 */
	public void hit( int damage , int angle){
		hitAngle = angle;
		remainingHealth = remainingHealth - damage;
		if ( remainingHealth <= 0 ){
			alive = false;
		}
	}
	
	
	/**
	 * Slows the zombosaur down by speed reduction amount
	 * @param speedReduction
	 */
	public void slow( int speedReduction ){
		currentSpeed = speed - speedReduction;
		
		if ( currentSpeed <= 0 ){
			currentSpeed = 1;
		}
	}
	
	/**
	 * Either makes the zombosaur take a step or do a step in it's death sequence(flying off the screen)
	 */
	public boolean update(TrailTile nextTile){
		if(alive){
			return step(nextTile);
		}
		else{
			deathSequence();
			return false;
		}
	}
	
	/**
	 * Makes the zombosaur fly off the screen. Only called when zombosaur's alive flag is false.
	 * 
	 */
	public void deathSequence(){
		
		xPos += (((float)this.flyawaySpeed/Controller.ticksPerSecond)*Math.cos((hitAngle+10)*Math.PI/180));
		yPos -= (((float)this.flyawaySpeed/Controller.ticksPerSecond)*Math.sin((hitAngle+10)*Math.PI/180));
		rotateDegreesCW(30);
		
		if(xPos < 0 || xPos > Map.MAP_WIDTH || yPos < 0 || yPos > Map.MAP_HEIGHT){
			finishedDying = true;
		}
	}
	
	/**
	 * Makes the Zombosaur move forward
	 * 
	 * @return true if the zombosaur enters a new trail tile
	 */
	public boolean step(TrailTile nextTile){
		
		tickCounter++;
		if(tickCounter >= stepPeriod*((float)Controller.ticksPerSecond)){
			if(currentImageName.equals(imageName1)) currentImageName = imageName2;
			else currentImageName = imageName1;
			tickCounter = 0;
		}
		
		if(nextTile.hasItem()) {
			System.out.println(nextTile.hasItem());
			DefensiveItem nextItem = ((DefensiveItem) nextTile.getItem());
			nextItem.onContact(this);
			if(nextItem.isDestroyed()){
				nextTile.removeItem();
			}
		}
		
		int preStepTileX = 0;		//tile coordinates where the center of the zombosaur is initially
		int preStepTileY = 0;
		int postStepTileX = 0;
		int postStepTileY = 0;

		if(direction == 0 || direction == 90){	//we need to decide where the beginning of the next tile is depending on direction
			preStepTileX = (int)(xPos-0.5);		
			preStepTileY = (int)(yPos-0.5);
		}
		else if(direction == 180 || direction == 270){
			preStepTileX = (int)(xPos+0.4);
			preStepTileY = (int)(yPos+0.4);
		}
		else {
			System.err.println("The Zombosaurs direction was not a multiple of 90! It was"+direction);
		}
		
		//take a step forward
		xPos += (((float)this.currentSpeed/Controller.ticksPerSecond)*Math.cos(direction*Math.PI/180));
		yPos += (((float)this.currentSpeed/Controller.ticksPerSecond)*Math.sin(direction*Math.PI/180));
		
		if(direction == 0 || direction == 90){	//we need to decide where the beginning of the next tile is depending on direction
			postStepTileX = (int)(xPos-0.5);		
			postStepTileY = (int)(yPos-0.5);
		}
		else if(direction == 180 || direction == 270){
			postStepTileX = (int)(xPos+0.4);
			postStepTileY = (int)(yPos+0.4);
		}
		else {
			System.err.println("The Zombosaurs direction was not a multiple of 90! It was"+direction);
		}
		
		//System.out.println("Direction = "+direction+", Pre = "+preStepTileX+" "+preStepTileY+", Post = "+postStepTileX+" "+postStepTileY);
		
		if(postStepTileX != preStepTileX || postStepTileY != preStepTileY){
			//System.out.println("Zombo just left tile "+currentTile.getX()+ " "+currentTile.getY());
			return true;
		}
		
		return false;
	}
	
	/**
	 * Check if the zombosaur needs to rotate or do something else for the next trail tile
	 */
	public void checkNextTileAndRotate(TrailTile nextTile){
		//change the direction based on the next trail tile
		int nextX = nextTile.getGridCoordinates().getX();	//the x of the next tile
		int nextY = nextTile.getGridCoordinates().getY();
		int thisX = currentTile.getX();	
		int thisY = currentTile.getY();
		int angle = (int)(Math.atan2(nextY-thisY, nextX-thisX)*180/Math.PI);
		
		setDirection(angle);
	}
	
	
	/**
	 * Stops the Zombosaur
	 */
	public void stop(){
		currentSpeed = 0;
	}
	
	
	/**
	 *  Brings the zombosaur back to its default speed
	 */
	public void resumeSpeed(){
		currentSpeed = speed;
	}
	
	/**
	 * Rotates the zombosaur
	 */
	public void rotateDegreesCW(int degrees){
		setDirection(this.direction + degrees);
	}
	
	/**
	 * Getters and setters
	 */
	public void setAlive(boolean alive) {
		this.alive = alive;
	}
	
	public boolean isAlive(){
		return alive;
	}
	
	public int getSpeed() {
		return speed;
	}

	public void setSpeed(int speed) {
		this.speed = speed;
	}

	public int getCurrentSpeed() {
		return currentSpeed;
	}

	public void setCurrentSpeed(int currentSpeed) {
		this.currentSpeed = currentSpeed;
	}

	public int getRemainingHealth() {
		return remainingHealth;
	}

	public void setRemainingHealth(int remainingHealth) {
		this.remainingHealth = remainingHealth;
	}

	public int getDamage() {
		return damage;
	}

	public void setDamage(int damage) {
		this.damage = damage;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getImageName() {
		return currentImageName;
	}

	public void setImageName(String imageName) {
		this.currentImageName = imageName;
	}

	public float getxPos() {
		return xPos;
	}

	public void setxPos(float xPos) {
		this.xPos = xPos;
	}

	public float getyPos() {
		return yPos;
	}

	public void setyPos(float yPos) {
		this.yPos = yPos;
	}
	
	public int getDirection() {
		return direction;
	}

	public void setDirection(int direction) {
		this.direction = (direction+360)%360;
	}

	public void setCurrentTile(TrailTile tile){
		this.currentTile = tile;
	}
	
	public TrailTile getCurrentTile(){
		return currentTile;
	}
	
	public float getStepPeriod() {
		return stepPeriod;
	}

	public void setStepPeriod(float stepPeriod) {
		this.stepPeriod = stepPeriod;
	}

	
	public boolean isFinishedDying() {
		return finishedDying;
	}
	
}